home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
fish
/
001-100
/
001-025
/
018
/
amigadisplay
/
main.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-17
|
12KB
|
346 lines
/* AmigaDisplay: A "smart display" terminal emulator for the Amiga
*
* Based on the AmigaTerm program by Michael Mounier, enhanced by Don Woods.
* This version emulates either a "dumb terminal" or a DataMedia 2500.
* Mounier's version was (c) 1985 but was freely distributed. Woods's
* rewrite is (c) 1986 and is likewise available if due credit is given.
*
* The DM2500 supports a special command sequence used at Stanford to display
* up to 128 different character glyphs, and also supports various special
* interpretations applied to the ALT, AMIGA, and F# keys (again for use at
* Stanford). These features, and the type of display being emulated, should
* be fairly easy to change (e.g., if someone would rather emulate a VT100).
*
* The emulator also provides a variety of bell volumes (just for kicks), and
* file send/capture, but NOT the so-called "xmodem" features. The send/
* capture stuff uses a requester to avoid mucking up the display region.
*/
/****************************************\
* This file is the main program (main.c) *
\****************************************/
#include <exec/types.h>
#include <exec/exec.h>
#include <graphics/gfxbase.h>
#include <graphics/gfx.h>
#include <graphics/text.h>
#include <devices/serial.h>
#include <devices/keymap.h>
#include <stdio.h>
#include <intuition/intuitionbase.h>
#include <intuition/intuition.h>
/*
* Library definitions; shared with the other modules
*/
#define INTUITION_REV 1
#define GRAPHICS_REV 1
#define FONT_REV 1
struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;
struct DiskfontBase *DiskfontBase = NULL;
/*
* Functions imported from other modules
*/
/* in intuit.c */
extern InitWindowStuff(struct Window *);
extern CleanUpWindow(struct Window *);
extern FileMenu(struct Window *, int, FILE **, FILE **, int *);
/* in dpy.c */
extern SetUpDisplay(struct Window *, int);
extern char Emit(char);
extern NeedQuote(char);
/* in beep.c */
extern InitAudio(int);
extern SetBeeper(int);
extern Beep();
extern CleanUpBeeper();
/*
* Globals and externals for using the serial port
*/
extern struct MsgPort *CreatePort();
static struct IOExtSer *inreq = NULL, *outreq = NULL;
static char inbuf[2], outbuf[2];
/*
* MAIN PROGRAM
*/
main() {
char c;
int buckied; /* see ToAsc for details */
int proceed = TRUE, fileFlags = 0;
FILE *receive = NULL, *send = NULL;
struct Window *mywindow;
struct IntuiMessage *message; /* msg struct for GetMsg */
/* Bits set in fileFlags */
#define RAWCAPTURE 1 /* include ctrl chars in captured file */
#define SENDLFASCR 2 /* translate LFs to CRs when sending */
/* Emulator window structure */
static struct NewWindow newWindow = {
0, 0, 640, 200,
0,
1,
RAWKEY | MENUPICK | GADGETUP | REQCLEAR,
SMART_REFRESH | ACTIVATE | BORDERLESS,
NULL, NULL, NULL, NULL, NULL,
100, 35, 640, 200, /* min/max dims, unused since sizegadget omitted */
WBENCHSCREEN};
IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library", INTUITION_REV);
GfxBase = (struct GfxBase *)
OpenLibrary("graphics.library", GRAPHICS_REV);
DiskfontBase = (struct DiskfontBase *)
OpenLibrary("diskfont.library", FONT_REV);
if (IntuitionBase == NULL || GfxBase == NULL || DiskfontBase == NULL)
GoAway("Can't open libraries", NULL);
if ((mywindow = (struct Window *)OpenWindow(&newWindow)) == NULL)
GoAway("Can't open window", NULL);
/* Open serial device once and copy the initialised ioreq; */
/* that way we can have exclusive access with two ports */
inreq = (struct IOExtSer *)AllocMem(sizeof(*inreq), MEMF_PUBLIC|MEMF_CLEAR);
inreq->IOSer.io_Message.mn_ReplyPort = CreatePort("SerialRead", 0);
if (OpenDevice(SERIALNAME, NULL, inreq, NULL))
GoAway("Can't open Serial port", mywindow);
inreq->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
inreq->IOSer.io_Command = SDCMD_SETPARAMS;
inreq->io_ReadLen = inreq->io_WriteLen = 8;
DoIO(inreq);
inreq->IOSer.io_Length = 1;
outreq = (struct IOExtSer *)AllocMem(sizeof(*outreq), MEMF_PUBLIC);
movmem((char *)inreq, (char *)outreq, sizeof(*inreq));
outreq->IOSer.io_Message.mn_ReplyPort = CreatePort("SerialWrite", 0);
inreq->IOSer.io_Command = CMD_READ;
inreq->IOSer.io_Data = (APTR)inbuf;
outreq->IOSer.io_Command = CMD_WRITE;
outreq->IOSer.io_Data = (APTR)outbuf;
if (InitWindowStuff(mywindow)) {
CloseDevice(inreq);
CloseDevice(outreq);
GoAway("Not enough memory", mywindow);
}
/* Finish initialisation */
InitAudio(1);
SetAPen(mywindow->RPort, 1);
SetUpDisplay(mywindow, 1);
SetBaud(1);
BeginIO(inreq);
while (proceed) {
/* wait for something to do */
if (send == NULL)
Wait((1 << inreq->IOSer.io_Message.mn_ReplyPort->mp_SigBit)
| (1 << mywindow->UserPort->mp_SigBit));
if (CheckIO(inreq)) { /* receive a char from the host */
WaitIO(inreq);
c = inbuf[0] & 0x7F;
BeginIO(inreq);
if (fileFlags & RAWCAPTURE) Emit(c); else c = Emit(c);
/* Emit returns hex 80 if char is non-printing */
if (receive != NULL && c < 0x80) /* capture this character */
if ((c >= ' ' && c <= '~') || c == '\n' || c == '\t')
putc(c, receive); /* always capture these chars */
else if (fileFlags & RAWCAPTURE) {
if (c == 0x7F) fputs("^?", receive);
else {putc('^', receive); putc(c+0x40, receive);}
}
}
else if (send != NULL) { /* send file (only if host not talking) */
if ((c=getc(send)) != EOF)
Ship(c == '\n' && (fileFlags & SENDLFASCR) ? '\r' : c);
else {
fclose(send);
send = NULL;
FileMenu(mywindow, 99, &receive, &send, &fileFlags);
}
}
while (message = (struct IntuiMessage *)GetMsg(mywindow->UserPort)) {
ULONG class;
USHORT code, qual;
class = message->Class;
code = message->Code;
qual = message->Qualifier;
ReplyMsg(message);
switch (class) {
case RAWKEY: /* user has touched the keyboard */
if ((buckied = ToAsc(code, qual)) >= 0) {
if (buckied & 0x100) Ship(0x80);
else if (NeedQuote(c = buckied & 0x7F)) Ship(0);
Ship(buckied & 0xFF);
}
else if (buckied != -99) { /* function key */
Ship(0); /* send NUL, number, CR */
Ship('0'+((-buckied)/10));
Ship('0'+((-buckied)%10));
Ship('\r');
}
break;
case MENUPICK:
if (code != MENUNULL) switch (MENUNUM(code)) {
case 0: FileMenu(mywindow, ITEMNUM(code), &receive, &send, &fileFlags); break;
case 1: BaudMenu(code); break;
case 2: SetUpDisplay(NULL, ITEMNUM(code)); break;
case 3:
SetBeeper(ITEMNUM(code));
if (Beep()) DisplayBeep(mywindow->WScreen);
break;
case 4: proceed = WindowMenu(mywindow, code); break;
}
break;
} /* end of switch (class) */
} /* end of while (message) */
} /* end of while (proceed) */
/* It must be time to quit */
CloseDevice(inreq);
CloseDevice(outreq);
CleanUpWindow(mywindow);
CleanUpBeeper();
GoAway(NULL, mywindow); /* exit will close send/receive files if open */
} /* end of main */
/*
* Function to clean up however much stuff got started
*/
static GoAway(text, w) char *text; struct Window *w; {
if (w) CloseWindow(w);
if (inreq) {
DeletePort(inreq->IOSer.io_Message.mn_ReplyPort);
FreeMem(inreq, sizeof(*inreq));
}
if (outreq) {
DeletePort(outreq->IOSer.io_Message.mn_ReplyPort);
FreeMem(outreq, sizeof(*outreq));
}
if (IntuitionBase != NULL) CloseLibrary(IntuitionBase);
if (GfxBase != NULL) CloseLibrary(GfxBase);
if (DiskfontBase != NULL) CloseLibrary(DiskfontBase);
if (text) {printf("ERROR: %s\n", text); exit(100);}
exit(FALSE);
}
/*
* Quickie to ship one char to serial port
*/
static Ship(c) char c; {
outbuf[0] = c;
DoIO(outreq);
}
/*
* Menu routines (FileMenu is external)
*/
static BaudMenu(code) USHORT code; {
AbortIO(inreq);
SetBaud(ITEMNUM(code));
BeginIO(inreq);
}
static SetBaud(index) USHORT index; {
switch (index) {
case 0: inreq->io_Baud = 300; break;
case 1: inreq->io_Baud = 1200; break;
case 2: inreq->io_Baud = 2400; break;
case 3: inreq->io_Baud = 4800; break;
case 4: inreq->io_Baud = 9600; break;
}
inreq->IOSer.io_Command = SDCMD_SETPARAMS;
DoIO(inreq);
inreq->IOSer.io_Command = CMD_READ;
}
static WindowMenu(w, code) struct Window *w; USHORT code; {
/* returns TRUE unless window is supposed to close */
switch (ITEMNUM(code)) {
case 0: WindowToBack(w); break;
case 1: WindowToFront(w); break;
case 2: return(FALSE);
}
return(TRUE);
}
/*
* Function to convert raw key data into ascii chars
*/
/* The system at Stanford uses 9-bit characters. The bottom 7 bits are normal
* ascii, although there are visible characters associated with the ctrl chars.
* (E.g., ^H prints as lambda, ^U as existential quantifier, ^A as down-arrow.)
* The 0x80 bit and 0x100 bit are called "bucky bits" (see Hacker's Dictionary)
* and are typically used to distinguish command chars from regular typein.
* These bits are set by some extra shift keys on the Stanford keyboards, called
* CONTROL and META. When talking to Stanford across an 8-bit serial line,
* one sends CONTROL in the parity bit and META by a prefixed char (0x80).
* This emulator interprets ALT as CONTROL, AMIGA as META, and CTRL as the
* standard-ascii control key. If you don't need the bucky-bit features, just
* don't hold down the ALT or AMIGA keys while typing, and you'll be fine.
*
* This function returns the 7-bit ascii code for the given keyboard action,
* plus bucky-bits in 0x180. If the keyboard action is a no-op (e.g., key up,
* or shift key down), it returns -99. Function keys return -(10+key#), or
* -key# if shifted.
*/
/* qualifier bits */
#define LSHIFT (1<<0)
#define RSHIFT (1<<1)
#define SHLOCK (1<<2)
#define CTL (1<<3) /* the real "ctrl" key */
#define LCTRL (1<<4) /* ALT keys set parity bit */
#define RCTRL (1<<5)
#define LMETA (1<<6) /* Amiga keys set 9th bit */
#define RMETA (1<<7)
static ToAsc(code, qual) USHORT code, qual; {
char c;
static char *map = "\
`1234567890-=\\?0qwertyuiop[]?123asdfghjkl;'??456\
?zxcvbnm,./?.789 \b\t\n\r\33\177???-?\13\f";
if (code >= 0x50 && code <= 0x59) /* function keys */
return((qual & (LSHIFT|RSHIFT) ? -1 : -11) - (c = code&0xF));
if (code <= 0x4D) c = map[code];
else if (code == 0x5F) c = 0; /* HELP key translates into NUL */
else return(-99);
if (c == '?') return(-99);
if (qual & (LSHIFT|RSHIFT)) {
if (c >= 'a' && c <= 'z') c -= 0x20;
else if (c >= ',' && c <= '=') {
code = c - ','; /* sidestep compiler bug re subscript exprs */
c = "<_>?)!@#$%^&*(::<+"[code];
}
else if (c >= '[' && c <= '`') {
code = c - '['; /* ditto */
c = "{|}^_~"[code];
}
else if (c == '\'') c = '"';
} /* end shift */
else if ((qual & SHLOCK) && c >= 'a' && c <= 'z') c -= 0x20;
if (qual & CTL) c &= 0x1F;
return(c + (qual & (LCTRL|RCTRL) ? 0x80 : 0)
+ (qual & (LMETA|RMETA) ? 0x100 : 0));
} /* end of ToAsc */